package com.pai4j.message.subscription;

import com.pai4j.message.model.MessageContext;
import com.pai4j.message.model.SubscriptionConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * 消息订阅实现
 * 基于内存的订阅管理（生产环境建议使用Redis）
 *
 * @author PAI4J Team
 * @date 2025-11-01
 */
@Slf4j
@Component
@ConditionalOnProperty(prefix = "pai4j.message.subscription", name = "enabled", havingValue = "true", matchIfMissing = false)
public class MessageSubscriptionImpl implements MessageSubscription {

    /**
     * 订阅配置存储
     * key: subscriptionId, value: SubscriptionConfig
     */
    private final Map<String, SubscriptionConfig> subscriptions = new ConcurrentHashMap<>();

    /**
     * 用户订阅索引
     * key: userId, value: List<subscriptionId>
     */
    private final Map<String, List<String>> userSubscriptionIndex = new ConcurrentHashMap<>();

    /**
     * 订阅者列表
     */
    private final Map<String, Subscriber> subscribers = new ConcurrentHashMap<>();

    @Override
    public String subscribe(SubscriptionConfig config) {
        if (config == null || config.getUserId() == null) {
            throw new IllegalArgumentException("订阅配置或用户ID不能为空");
        }

        try {
            // 生成订阅ID
            String subscriptionId = config.getSubscriptionId();
            if (subscriptionId == null || subscriptionId.isEmpty()) {
                subscriptionId = generateSubscriptionId();
                config.setSubscriptionId(subscriptionId);
            }

            // 设置时间
            config.setCreateTime(LocalDateTime.now());
            config.setUpdateTime(LocalDateTime.now());

            // 保存订阅配置
            subscriptions.put(subscriptionId, config);

            // 更新用户订阅索引
            userSubscriptionIndex.computeIfAbsent(config.getUserId(), k -> new ArrayList<>())
                    .add(subscriptionId);

            log.info("用户订阅成功: userId={}, subscriptionId={}, type={}", 
                    config.getUserId(), subscriptionId, config.getSubscriptionType());

            return subscriptionId;

        } catch (Exception e) {
            log.error("订阅失败: {}", e.getMessage(), e);
            throw new RuntimeException("订阅失败", e);
        }
    }

    @Override
    public void unsubscribe(String subscriptionId) {
        if (subscriptionId == null || subscriptionId.isEmpty()) {
            return;
        }

        try {
            SubscriptionConfig config = subscriptions.remove(subscriptionId);
            if (config != null) {
                // 从用户订阅索引中移除
                List<String> userSubs = userSubscriptionIndex.get(config.getUserId());
                if (userSubs != null) {
                    userSubs.remove(subscriptionId);
                }

                log.info("取消订阅成功: userId={}, subscriptionId={}", 
                        config.getUserId(), subscriptionId);
            }
        } catch (Exception e) {
            log.error("取消订阅失败: {}", e.getMessage(), e);
        }
    }

    @Override
    public List<SubscriptionConfig> getUserSubscriptions(String userId) {
        if (userId == null || userId.isEmpty()) {
            return Collections.emptyList();
        }

        List<String> subscriptionIds = userSubscriptionIndex.get(userId);
        if (subscriptionIds == null || subscriptionIds.isEmpty()) {
            return Collections.emptyList();
        }

        return subscriptionIds.stream()
                .map(subscriptions::get)
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
    }

    @Override
    public SubscriptionConfig getSubscription(String subscriptionId) {
        return subscriptions.get(subscriptionId);
    }

    @Override
    public void updateSubscription(SubscriptionConfig config) {
        if (config == null || config.getSubscriptionId() == null) {
            throw new IllegalArgumentException("订阅配置或订阅ID不能为空");
        }

        try {
            config.setUpdateTime(LocalDateTime.now());
            subscriptions.put(config.getSubscriptionId(), config);

            log.info("更新订阅成功: userId={}, subscriptionId={}", 
                    config.getUserId(), config.getSubscriptionId());

        } catch (Exception e) {
            log.error("更新订阅失败: {}", e.getMessage(), e);
            throw new RuntimeException("更新订阅失败", e);
        }
    }

    @Override
    public boolean isSubscribed(String userId, MessageContext context) {
        if (userId == null || context == null) {
            return false;
        }

        List<SubscriptionConfig> userConfigs = getUserSubscriptions(userId);
        if (userConfigs.isEmpty()) {
            return false;
        }

        // 检查是否有匹配的订阅
        for (SubscriptionConfig config : userConfigs) {
            if (matchesSubscription(context, config)) {
                return true;
            }
        }

        return false;
    }

    @Override
    public void notifySubscribers(MessageContext context) {
        if (context == null) {
            return;
        }

        try {
            // 获取所有订阅者
            List<String> subscriberIds = getSubscribers(context);

            if (subscriberIds.isEmpty()) {
                log.debug("没有订阅者需要通知");
                return;
            }

            // 通知所有订阅者
            for (String subscriberId : subscriberIds) {
                Subscriber subscriber = subscribers.get(subscriberId);
                if (subscriber != null) {
                    try {
                        subscriber.onMessage(context);
                        log.debug("通知订阅者成功: subscriberId={}", subscriberId);
                    } catch (Exception e) {
                        log.error("通知订阅者失败: subscriberId={}, error={}", 
                                subscriberId, e.getMessage(), e);
                    }
                }
            }

            log.info("通知订阅者完成: count={}", subscriberIds.size());

        } catch (Exception e) {
            log.error("通知订阅者失败: {}", e.getMessage(), e);
        }
    }

    @Override
    public List<String> getSubscribers(MessageContext context) {
        if (context == null) {
            return Collections.emptyList();
        }

        Set<String> subscriberSet = new HashSet<>();

        // 遍历所有订阅配置
        for (SubscriptionConfig config : subscriptions.values()) {
            if (matchesSubscription(context, config)) {
                subscriberSet.add(config.getUserId());
            }
        }

        return new ArrayList<>(subscriberSet);
    }

    /**
     * 注册订阅者
     */
    public void registerSubscriber(Subscriber subscriber) {
        if (subscriber != null && subscriber.getSubscriberId() != null) {
            subscribers.put(subscriber.getSubscriberId(), subscriber);
            log.info("注册订阅者: subscriberId={}, type={}", 
                    subscriber.getSubscriberId(), subscriber.getSubscriberType());
        }
    }

    /**
     * 取消注册订阅者
     */
    public void unregisterSubscriber(String subscriberId) {
        subscribers.remove(subscriberId);
        log.info("取消注册订阅者: subscriberId={}", subscriberId);
    }

    /**
     * 判断消息是否匹配订阅配置
     */
    private boolean matchesSubscription(MessageContext context, SubscriptionConfig config) {
        if (config == null || !config.getEnabled()) {
            return false;
        }

        // 检查静默时段
        if (config.isInQuietPeriod()) {
            return false;
        }

        // 检查消息类型
        if (context.getMessageDTO() != null) {
            String messageType = context.getMessageDTO().getClass().getSimpleName();
            if (!config.isSubscribedToMessageType(messageType)) {
                return false;
            }
        }

        // 检查资源
        if (context.getResourceInfo() != null) {
            String resourceId = context.getResourceInfo().getResourceId();
            if (!config.isSubscribedToResource(resourceId)) {
                return false;
            }
        }

        // 检查发送者
        if (context.getSenderId() != null) {
            if (!config.isSubscribedToUser(context.getSenderId())) {
                return false;
            }
        }

        return true;
    }

    /**
     * 生成订阅ID
     */
    private String generateSubscriptionId() {
        return "SUB-" + System.currentTimeMillis() + "-" + 
               (int)(Math.random() * 10000);
    }
}

